﻿using System;
using System.IO;
using System.Reflection;

namespace CommonUtils.Logging.LoggingProviders
{
    ///<summary>
    /// Logging provider for saving log to file
    ///</summary>
    public class FileLoggingProvider: BaseLoggingProvider
    {
        #region Constants

        /// <summary>
        /// Log files extension
        /// </summary>
        private const string LogFileExtension = "log";

        #endregion

        #region Properties

        private string LogFilePath
        {
            get;
            set;
        }

        /// <summary>
        /// Stream for logging
        /// </summary>
        private FileStream LogFileStream
        {
            get;
            set;
        }

        /// <summary>
        /// Stream writer for logging
        /// </summary>
        private StreamWriter LogStreamWriter
        {
            get;
            set;
        }

        /// <summary>
        /// Object to set locks on log file writing
        /// </summary>
        private readonly object lockObject = new object();

        /// <summary>
        /// Gets default log file name
        /// </summary>
        private static string DefaultLogFileName
        {
            get
            {
                Assembly entryAssembly = Assembly.GetEntryAssembly();
                return Path.Combine(Path.GetDirectoryName(entryAssembly.Location),
                                    string.Format("{0}.{1}", entryAssembly.GetName().Name, LogFileExtension));
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public FileLoggingProvider(): this(DefaultLogFileName)
        {
        }

        /// <summary>
        /// Constructor with logging level specified
        /// </summary>
        /// <param name="loggingLevel">Logging level</param>
        public FileLoggingProvider(MessageType loggingLevel): this(loggingLevel, DefaultLogFileName)
        {
        }

        /// <summary>
        /// Constructor with file name specified
        /// </summary>
        /// <param name="fileName">File to log into</param>
        public FileLoggingProvider(string fileName): this(DefaultLoggingLevel, fileName)
        {
        }

        /// <summary>
        /// Constructor with logging level and file name specified
        /// </summary>
        /// <param name="loggingLevel">Logging level</param>
        /// <param name="fileName">File to log into</param>
        public FileLoggingProvider(MessageType loggingLevel, string fileName): base(loggingLevel)
        {
            LogFilePath = fileName;
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Initialization of logging provider
        /// </summary>
        public override void InitializeLog()
        {
            base.InitializeLog();

            LogFileStream = new FileStream(LogFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
            LogStreamWriter = new StreamWriter(LogFileStream);
        }

        /// <summary>
        /// Log message
        /// </summary>
        public override void LogMessageImpl(DateTime dateTime, MessageType messageType, string message)
        {
            lock (lockObject)
            {
                LogStreamWriter.WriteLine(string.Format("{0} - {1}: {2}", DateTime.Now, messageType, message));
                LogStreamWriter.Flush();
            }
        }

        /// <summary>
        /// Initialization of logging provider
        /// </summary>
        public override void FinalizeLog()
        {
            base.FinalizeLog();
            LogStreamWriter.WriteLine();
            LogStreamWriter.Close();
            LogFileStream.Close();
        }

        #endregion
    }
}